﻿using DataModels.Entities.HomeService;
using DataModels.Enums.Home;
using SqlSugar;
using System.Text.Json;
using Utils;
using static DataModels.Enums.GeneralEnum;

namespace Services.Home
{
    public class ServiceTimeManagementService() // :BaseService(db)
    {
        // 服务时间规则示例
        //{
        //  "productId": "a1b2c3d4-e5f6-a7b8-c9d0-e1f2a3b4c5d6",
        //  "ruleName": "工作日服务时间",
        //  "ruleType": 2, // 1-固定日期，2-周规则，3-月规则
        //  "startDate": "2023-11-01",
        //  "endDate": null,
        //  "weekMask": 22, // 二进制 10110 (周一、三、五)
        //  "timeSlots": [
        //    {
        //      "startTime": "09:00",
        //      "endTime": "12:00",
        //      "availableSlots": 5,
        //      "isAllDay": false
        //    },
        //    {
        //      "startTime": "13:00",
        //      "endTime": "18:00",
        //      "availableSlots": 8,
        //      "isAllDay": false
        //    }
        //  ],
        //  "isEnabled": true
        //}
        #region 规则管理
        /// <summary>
        /// 添加新的服务时间规则
        /// </summary>
        public Guid AddHomeServiceProductTimeRule(SqlSugarClient db,HomeServiceProductTimeRule rule)
        {
            // 验证规则有效性
            ValidateHomeServiceProductTimeRule(rule);

            // 插入数据库
            rule.UUID = Guid.NewGuid();
            rule.CreateTime = DateTime.Now;
            rule.UpdateTime = DateTime.Now;

            db.Insertable(rule).ExecuteCommand();
            return rule.UUID;
        }

        /// <summary>
        /// 更新服务时间规则
        /// </summary>
        public void UpdateHomeServiceProductTimeRule(SqlSugarClient db,HomeServiceProductTimeRule rule)
        {
            // 验证规则有效性
            ValidateHomeServiceProductTimeRule(rule);

            // 更新数据库
            rule.UpdateTime = DateTime.Now;

            db.Updateable(rule)
               .IgnoreColumns(it => new { it.CreateTime, it.IsDeleted })
               .ExecuteCommand();
        }

        /// <summary>
        /// 删除服务时间规则
        /// </summary>
        public void DeleteHomeServiceProductTimeRule(SqlSugarClient db,Guid ruleId)
        {
            db.Updateable<HomeServiceProductTimeRule>()
               .SetColumns(it => new HomeServiceProductTimeRule { IsDeleted = Status.Enable, UpdateTime = DateTime.Now })
               .Where(it => it.UUID == ruleId)
               .ExecuteCommand();
        }

        /// <summary>
        /// 获取商品的所有服务时间规则
        /// </summary>
        public List<HomeServiceProductTimeRule> GetHomeServiceProductTimeRules(SqlSugarClient db, Guid productId)
        {
            return db.Queryable<HomeServiceProductTimeRule>()
               .Where(it => it.ProductUUID == productId && it.IsDeleted == Status.Disable)
               .OrderBy(it => it.StartDate)
               .ToList();
        }
        #endregion

        #region 时间段计算
        /// <summary>
        /// 获取指定日期的可用服务时间段
        /// </summary>
        public List<TimeSlotConfig> GetAvailableTimeSlots(SqlSugarClient db,Guid productId, DateTime date)
        {
            // 查询适用于该日期的所有规则
            var applicableRules = GetApplicableRules(db,productId, date);

            // 合并并解析时间段配置
            var timeSlots = new List<TimeSlotConfig>();
            foreach (var rule in applicableRules)
            {
                var slots = JsonSerializer.Deserialize<List<TimeSlotConfig>>(rule.TimeSlotsJson);
                foreach (TimeSlotConfig slot in slots)
                {
                    slot.ProductTimeRuleUUID = rule.UUID;
                }
                timeSlots.AddRange(slots);
            }

            // 处理冲突并返回最终可用时间段
            return ResolveTimeSlotConflicts(timeSlots);
        }

        /// <summary>
        /// 获取指定日期范围内的可用服务时间段
        /// </summary>
        public Dictionary<DateTime, List<TimeSlotConfig>> GetAvailableTimeSlotsInRange(
            SqlSugarClient db,
            Guid productId,
            DateTime startDate,
            DateTime endDate)
        {
            var result = new Dictionary<DateTime, List<TimeSlotConfig>>();

            //查时间范围内的订单数量
            List<HomeServiceOrder> Orders = db.Queryable<HomeServiceOrder>()
                .Where(hso => hso.IsDeleted == Status.Disable)
                .Where(hso =>
                    hso.OrderStatus == HomeServcieOrderStatus.PendingPayment ||
                    hso.OrderStatus == HomeServcieOrderStatus.Paid ||
                    hso.OrderStatus == HomeServcieOrderStatus.Completed ||
                    hso.OrderStatus == HomeServcieOrderStatus.IsComment
                )
                .Where(hso => hso.ProductUUID == productId)
                .Where(hso => hso.ServiceStartTime >= startDate.Date)
                .Where(hso => hso.ServiceStartTime < endDate.Date.AddDays(1))
                .ToList()
                ;
            // 遍历日期范围
            for (var date = startDate; date <= endDate; date = date.AddDays(1))
            {
                var slots = GetAvailableTimeSlots(db,productId, date);
                if(slots.Count > 0)
                {
                    foreach (var slot in slots)
                    {
                        TimeSpan.TryParse(slot.StartTime, out TimeSpan stime);
                        TimeSpan.TryParse(slot.EndTime, out TimeSpan etime);
                        int ct = Orders.Where(o => o.ServiceStartTime >= date.Date.Add(stime) && o.ServiceStartTime<= date.Date.Add(etime)).Count();
                        slot.AvailableSlots = slot.AvailableSlots - ct < 0 ? 0 : slot.AvailableSlots - ct;
                    }
                    result[date] = slots;
                }
            }
            return result;
        }
        #endregion

        #region 辅助方法
        /// <summary>
        /// 获取适用于指定日期的规则
        /// </summary>
        private List<HomeServiceProductTimeRule> GetApplicableRules(SqlSugarClient db,Guid productId, DateTime date)
        {
            // 预计算左移值 (1 << dayOfWeek)
            int dayOfWeek = (int)date.DayOfWeek;
            int shiftValue = 1 << dayOfWeek;

            return db.Queryable<HomeServiceProductTimeRule>()
                .Where(r => r.ProductUUID == productId
                         && r.IsEnabled
                         && r.IsDeleted == Status.Disable
                         && r.StartDate <= date
                         && (r.EndDate == null || r.EndDate >= date)
                         && (r.RuleType == 1 ||
                             (r.RuleType == 2 && (r.WeekMask & shiftValue) != 0)))
                .ToList();
        }

        /// <summary>
        /// 处理时间段冲突
        /// </summary>
        private List<TimeSlotConfig> ResolveTimeSlotConflicts(List<TimeSlotConfig> slots)
        {
            if (!slots.Any()) return new List<TimeSlotConfig>();

            // 按开始时间排序
            var sortedSlots = slots.OrderBy(s => TimeSpan.Parse(s.StartTime)).ToList();
            var result = new List<TimeSlotConfig> { sortedSlots[0] };

            for (int i = 1; i < sortedSlots.Count; i++)
            {
                var current = sortedSlots[i];
                var last = result.Last();

                // 检查是否重叠
                if (TimeSpan.Parse(current.StartTime) < TimeSpan.Parse(last.EndTime))
                {
                    // 重叠时合并或覆盖（这里选择覆盖，可根据业务调整）
                    result[result.Count - 1] = current;
                }
                else
                {
                    // 不重叠则添加
                    result.Add(current);
                }
            }

            return result;
        }

        /// <summary>
        /// 验证服务时间规则有效性
        /// </summary>
        private void ValidateHomeServiceProductTimeRule(HomeServiceProductTimeRule rule)
        {
            if (rule.RuleType == 2 && rule.WeekMask == 0)
            {
                throw new MSGException("周规则必须指定至少一个星期几");
            }

            if (rule.EndDate.HasValue && rule.EndDate < rule.StartDate)
            {
                throw new MSGException("结束日期不能早于开始日期");
            }

            try
            {
                // 验证时间段配置格式
                var slots = JsonSerializer.Deserialize<List<TimeSlotConfig>>(rule.TimeSlotsJson);

                if (slots == null || !slots.Any())
                {
                    throw new MSGException("时间段配置不能为空");
                }

                // 验证每个时间段的有效性
                foreach (var slot in slots)
                {
                    if (string.IsNullOrEmpty(slot.StartTime) || string.IsNullOrEmpty(slot.EndTime))
                    {
                        throw new MSGException("时间段的开始时间和结束时间不能为空");
                    }

                    if (!TimeSpan.TryParse(slot.StartTime, out _) || !TimeSpan.TryParse(slot.EndTime, out _))
                    {
                        throw new MSGException("时间段格式不正确，应为HH:mm");
                    }

                    if (TimeSpan.Parse(slot.EndTime) <= TimeSpan.Parse(slot.StartTime))
                    {
                        throw new MSGException("结束时间必须晚于开始时间");
                    }
                }
            }
            catch (Exception ex)
            {
                throw new MSGException("时间段配置JSON格式错误");
            }
        }
        #endregion

        #region 预约管理
        /// <summary>
        /// 创建服务时间预约
        /// </summary>
        public async Task<Guid> CreateHomeServiceBookingAsync(SqlSugarClient db,HomeServiceBooking booking)
        {
            // 验证预约信息
            //ValidateHomeServiceBooking(booking);

            //获取已预约数
            TimeSpan.TryParse(booking.StartTime, out TimeSpan stime);
            TimeSpan.TryParse(booking.EndTime, out TimeSpan etime);
            DateTime sdate = booking.ServiceDate.Date.Add(stime);
            DateTime edate = booking.ServiceDate.Date.Add(etime);

            //查时间范围内的订单数量
            int BookingCount = await db.Queryable<HomeServiceOrder>()
                .Where(hso => hso.IsDeleted == Status.Disable)
                .Where(hso => 
                    hso.OrderStatus == HomeServcieOrderStatus.PendingPayment ||
                    hso.OrderStatus == HomeServcieOrderStatus.Paid ||
                    hso.OrderStatus == HomeServcieOrderStatus.Completed ||
                    hso.OrderStatus == HomeServcieOrderStatus.IsComment
                )
                .Where(hso => hso.ProductUUID == booking.ProductUUID)
                .Where(hso => hso.ServiceStartTime >= sdate)
                .Where(hso => hso.ServiceStartTime <= edate)
                .CountAsync()
                ;

            // 检查时间段可用性
            //CheckTimeSlotAvailability(db,booking.ProductUUID, booking.ServiceDate, booking.StartTime, booking.EndTime, BookingCount);

            try
            {
                //db.BeginTran();
                // 插入预约记录
                booking.UUID = Guid.NewGuid();
                booking.CreateTime = DateTime.Now;
                booking.UpdateTime = DateTime.Now;
                await db.Insertable(booking).ExecuteCommandAsync();

                // 更新服务时间规则的已预约数量
                UpdateTimeSlotBookingCount(
                    booking.ProductUUID,
                    booking.ServiceDate,
                    booking.StartTime,
                    booking.EndTime,
                    booking.BookingCount
                );

                //db.CommitTran();
                return booking.UUID;
            }
            catch (Exception ex)
            {
                //db.RollbackTran();
                throw new Exception("创建预约失败", ex);
            }
        }

        /// <summary>
        /// 更新服务时间规则的已预约数量
        /// </summary>
        private void UpdateTimeSlotBookingCount(Guid productId, DateTime serviceDate, string startTime, string endTime, int bookingCount)
        {
            // 如果使用规则动态计算，需要更新规则中的已预约数量
            //db.Updateable<HomeServiceProductTimeRule>()
            //    .SetColumns(r => new HomeServiceProductTimeRule
            //    {
            //        // 这里需要根据实际数据模型调整
            //        // 假设规则中存储了时间段信息
            //        // 实际实现可能需要更复杂的逻辑
            //    })
            //    .Where(r => r.ProductUUID == productId /* 其他条件 */)
            //    .ExecuteCommand();
        }

        /// <summary>
        /// 获取用户的预约列表
        /// </summary>
        public List<HomeServiceBooking> GetUserBookings(SqlSugarClient db,Guid userId, BookingStatus? status = null)
        {
            var query = db.Queryable<HomeServiceBooking>()
                .Where(b => b.UserID == userId && b.IsDeleted == Status.Disable);

            if (status.HasValue)
            {
                query = query.Where(b => b.BookingStatus == status.Value);
            }

            return query
                .OrderBy(b => b.CreateTime, OrderByType.Desc)
                .ToList();
        }

        /// <summary>
        /// 获取商品的预约列表
        /// </summary>
        public List<HomeServiceBooking> GetProductBookings(SqlSugarClient db,Guid productId, BookingStatus? status = null)
        {
            var query = db.Queryable<HomeServiceBooking>()
                .Where(b => b.ProductUUID == productId && b.IsDeleted == Status.Disable);

            if (status.HasValue)
            {
                query = query.Where(b => b.BookingStatus == status.Value);
            }

            return query
                .OrderBy(b => b.ServiceDate, OrderByType.Asc) 
                .OrderBy(b => b.StartTime, OrderByType.Asc)  
                .ToList();
        }

        /// <summary>
        /// 取消预约
        /// </summary>
        public void CancelHomeServiceBooking(SqlSugarClient db,Guid bookingId, string reason = null)
        {
            db.Updateable<HomeServiceBooking>()
                .SetColumns(b => new HomeServiceBooking
                {
                    BookingStatus = BookingStatus.Cancelled, // 已取消
                    Remark = reason,
                    UpdateTime = DateTime.Now
                })
                .Where(b => b.UUID == bookingId)
                .ExecuteCommand();

            // 释放预约名额
            ReleaseBookingSlots(db,bookingId);
        }

        /// <summary>
        /// 释放预约名额
        /// </summary>
        private void ReleaseBookingSlots(SqlSugarClient db,Guid bookingId)
        {
            // 获取预约信息
            var booking = db.Queryable<HomeServiceBooking>()
                .Where(b => b.UUID == bookingId && b.IsDeleted == Status.Disable)
                .First();

            if (booking == null)
            {
                throw new Exception("预约记录不存在");
            }

            // 减少已预约数量
            UpdateTimeSlotBookingCount(
                booking.ProductUUID,
                booking.ServiceDate,
                booking.StartTime,
                booking.EndTime,
                -booking.BookingCount // 负数表示释放名额
            );
        }
        #endregion

        #region 预约验证
        /// <summary>
        /// 验证预约信息
        /// </summary>
        private void ValidateHomeServiceBooking(HomeServiceBooking booking)
        {
            if (booking.ProductUUID == Guid.Empty)
            {
                throw new MSGException("商品ID不能为空");
            }

            if (booking.UserID == Guid.Empty)
            {
                throw new MSGException("用户ID不能为空");
            }

            if (string.IsNullOrEmpty(booking.ContactName))
            {
                throw new MSGException("联系人姓名不能为空");
            }

            if (string.IsNullOrEmpty(booking.ContactPhone))
            {
                throw new MSGException("联系电话不能为空");
            }

            if (booking.BookingCount <= 0)
            {
                throw new MSGException("预约数量必须大于0");
            }

            if (booking.ServiceDate < DateTime.Now.Date)
            {
                throw new MSGException("服务日期不能早于今天");
            }

            if (string.IsNullOrEmpty(booking.StartTime) || string.IsNullOrEmpty(booking.EndTime))
            {
                throw new MSGException("预约时间段不能为空");
            }

            TimeSpan startTime, endTime;
            if (!TimeSpan.TryParse(booking.StartTime, out startTime) || !TimeSpan.TryParse(booking.EndTime, out endTime))
            {
                throw new MSGException("时间段格式不正确，应为HH:mm");
            }

            if (endTime <= startTime)
            {
                throw new MSGException("结束时间必须晚于开始时间");
            }
        }

        /// <summary>
        /// 检查时间段可用性
        /// </summary>
        private void CheckTimeSlotAvailability(SqlSugarClient db,Guid productId, DateTime serviceDate, string startTime, string endTime, int bookingCount)
        {
            // 获取可用时间段
            var availableSlots = GetAvailableTimeSlots(db,productId, serviceDate);

            // 查找匹配的时间段
            var matchingSlot = availableSlots.FirstOrDefault(s =>
                s.StartTime == startTime && s.EndTime == endTime);

            if (matchingSlot == null)
            {
                throw new MSGException("所选时间段不可用");
            }

            if (matchingSlot.AvailableSlots <= bookingCount)
            {
                throw new MSGException($"所选时间段剩余名额不足，无法预约");
            }
        }
        #endregion
    }
}
